//+------------------------------------------------------------------+
//|                                                       ZigZag.mq4 |
//|                   Copyright 2006-2014, MetaQuotes Software Corp. |
//|                                              http://www.mql4.com |
//+------------------------------------------------------------------+
#property copyright   "2015-2020, HandGao."
#property link        "http://www.handgao.com"
#property description "账户分析工具"
#property version   "1.00"
#property strict

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1  Violet
 
static bool InpShowPanelGroup = true;       // 显示面板

#define ANALYSIS_SYMBOL_RATE_CNT 11
string g_arySymbolRate[ANALYSIS_SYMBOL_RATE_CNT] = {"期指主连","螺纹主连","豆粕主连","原油主连","PTA主连","聚丙烯主","甲醇主连","白糖主连","棉花主连","棕榈主连","鸡蛋主连"};

//+------------------------------------------------------------------+
//| 每日步骤                                                         |
//+------------------------------------------------------------------+
#define WARING_MIND_LEN 11
string g_waringMind[WARING_MIND_LEN]=
{
"交易理念：",
"1.认真关注胜率（趋势掌控力）和对错（计划执行力），最后必定盈利.",
"2.输钱的方式有多种，而赢钱只有一种，那就是不要输.",
"3.如果你做不到稳定盈利，那么你一定要摆脱稳定亏损.",
"4.我看对趋势却没有赚到钱才领悟，年轻的代价就是没有抵御住诱惑.",
"5.我赚到钱又亏掉就是没有像鳄鱼一样不动如山的等待.",
"",
"6.小心草坪现象、盈亏同源、沉默成本、赌徒谬论、幸存者偏差.",
"7.小心巨变效应、冰山原理、木桶理论.",
"8.评估市场性格、市场情绪、交易量、持仓量、止损率、量价比.",
"9.评估大阴阳数量、小阴阳数量、单边率、包含率、跳空、中枢扩张."
};

//+------------------------------------------------------------------+
//| 交易理念                                                         |
//+------------------------------------------------------------------+
#define WARING_EVERYDAY_LEN 16
string g_waringEveryday[WARING_EVERYDAY_LEN]=
{
"注意事项：",
"1.适用于连续性好，趋势性稳定的大盘股，如螺纹和ETF，忌上蹿下跳.",
"2.不要作死的去创新每日步骤，教训参考2019年交易笔记.",
"3.不要超过3个品种，不要轻易开发新品种，教训参考2019年交易笔记.",
"4.谨慎手动补遗漏仓，一般都会得到惨痛教训.",
"5.注意分辨率2500x1600下，屏幕缩最小判断1、3、5.",
"6.每日阅读一遍本内容.",
"",
"每日步骤：",
"1.开盘前：EA和穿透开启，缩小，结合日线设置135及上一个是否扩展.",
"2.收盘前：上一笔开/加仓是否变成头肩形态则设置保本止盈.",
"3.收盘后：结合日线复查135，EA无报错，文华看持仓、交易量、连续性.",
"",
"每周总结：",
"1.复盘本月盈亏率",
"2.评估止损率"
};

//+------------------------------------------------------------------+
//| mqh imports                                                      |
//+------------------------------------------------------------------+
#include <Waltz/WaltzDraw.mqh>
#include <Waltz/WaltzOrder.mqh>

//+------------------------------------------------------------------+
//| 初始化函数                                                       |
//+------------------------------------------------------------------+
int OnInit()
{
    // 启动定时器
	//EventSetTimer(10);
	
	// 创建按钮
    CreateBtnGroup(true);//InpShowPanelGroup);

	return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| 释放函数                                                         |
//+------------------------------------------------------------------+
int deinit()
{
   clearDraw();
   return(0);
}

//+------------------------------------------------------------------+
//|  每个tick跳动一次,仅用于指标,本指标从左往右计算                  |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,	        // 价格[] 数组的大小
				const int prev_calculated,		// 前一次调用处理的柱
				const datetime &time[],			// 时间
				const double &open[],			// 开盘价
				const double &high[],			// 最高价
				const double &low[],			// 最低价
				const double &close[],			// 收盘价
				const long& tick_volume[],		// 订单交易量
				const long& volume[],			// 真实交易量
				const int& spread[])			// 点差
{
    //
	static int lastBarNum = 0;
	int nDiffer = Bars-lastBarNum;
	if(nDiffer !=0)   // 出现新的k线时才处理一次，优化性能
	{
        //updateLeftBottomText();
		lastBarNum = Bars;
	}
	//----
	return(rates_total);
}

//+------------------------------------------------------------------+
//| 定时事件                                                         |
//+------------------------------------------------------------------+
void OnTimer()
{
	//updateLeftBottomText();
	//AnalysisHistoryInfo();
}

//+------------------------------------------------------------------+
//| 图表事件                                                         |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
	/*----------------------------------------------------------------------*/
    /*    点击在对象上                                                      */
    /*----------------------------------------------------------------------*/
	if(id==CHARTEVENT_OBJECT_CLICK)
	{
	    // 开关按钮
		if(sparam=="WaltzAnalysis_Button_ShowPanelGroup")
		{
            if(!InpShowPanelGroup)
            {
                InpShowPanelGroup  = true;
            }
            else
            {
                InpShowPanelGroup  = false;
            }
            CreateBtnGroup(InpShowPanelGroup);
        }
    }
	
	ChartRedraw();
}

//+------------------------------------------------------------------+
//| 创建/隐藏按钮组                                                  |
//+------------------------------------------------------------------+
void CreateBtnGroup(bool bCreate)
{
    // 画黑背景方框
    DrawBlackRectangle(bCreate,4000,clrBlack);//clrSilver);
    
    /*----------------------------------------------------------------------*/
    /*    创建开关按钮                                                      */
    /*----------------------------------------------------------------------*/
    DrawButton("WaltzAnalysis_Button_ShowPanelGroup", 60 * 1, 30 * 1, "账户",true,InpShowPanelGroup?clrRed:clrWhite);


    // 画分析
    AnalysisHistoryInfo(InpShowPanelGroup);
}



//+------------------------------------------------------------------+
//| 分析历史订单数据                                                 |
//+------------------------------------------------------------------+
#define DRAW_ROW_SPACE 400      // 一列和列的横向间距
#define DRAW_ROW_GROUP_CNT 5    // 一列的纵向有几个组
#define DRAW_CNT_IN_GROUP 11     // 一组内有几行8+1间隔
void AnalysisHistoryInfo(bool bShow)
{
    if(!bShow)
    {
        ClearHistoryOrderOnChar();
        return;
    }
    
    int nSymbrlCnt = 0;
    string lsSymbol[100] = {""};
    
    int nTotalOrders = OrdersHistoryTotal();      
    if(0 == nTotalOrders)
    {
        return;
    }
    
    // Add sum order symbol
    lsSymbol[nSymbrlCnt++] = "ALL";
    
    //+------------------------------------------------------------------+
    //| Record history order symbol (Remove Duplicates)                                                    
    //+------------------------------------------------------------------+
    double dBuyProfit = 0.0;
    double dSellProfit = 0.0;
    int nBuyOrderCnt = 0;
    int nSellOrderCnt = 0;
    double dSumCommission = 0.0;
    datetime dtOrderBeginTime = TimeCurrent();
    datetime dtOrderEndTime = datetime();
    double dCount = 0.0;
    for(int i=0; i<nTotalOrders; i++)
    { 
        if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY) && (OrderType()==OP_BUY || OrderType()==OP_SELL))
        {
            string strSymbol = OrderSymbol();
            bool bFind = false;
            for(int k = 0;k<nSymbrlCnt;++k)
            {
                if(lsSymbol[k] == strSymbol)
                    bFind = true;
            }
            if(!bFind && strSymbol!="")
            {
                lsSymbol[nSymbrlCnt++] = strSymbol;
            }
            
            // Record order begin and end Time
            if(dtOrderBeginTime > OrderOpenTime())
                dtOrderBeginTime = OrderOpenTime();
            if(dtOrderEndTime < OrderCloseTime())
                dtOrderEndTime = OrderCloseTime();
            dSumCommission += OrderCommission();
            
            dCount +=1.0; // OrderLots();
        }
    }
    
    int symbolInfoFontSize = 12;
    int nWaringFontSize = 14;
    int nTopLowFontSize = 16;
    //+------------------------------------------------------------------+
    //| Draw Top                                                    
    //+------------------------------------------------------------------+
    string txt = "";
    int nXPos = 10;
    int nYPosIndex = 0;
    // Time Begin: 2019-11-11 | End: 2019-12-11 
    nXPos = DRAW_ROW_SPACE * 0 + 5;
    txt = "Time Begin: "+TimeToStr(dtOrderBeginTime,TIME_DATE)+" | End: "+TimeToStr(dtOrderEndTime,TIME_DATE);//| Commission："+DoubleToStr(dSumCommission,2)+" | Avg："+DoubleToStr(dAvgCommission,2);
    DrawCornerText(txt,nXPos,nYPosIndex,clrRed,nTopLowFontSize,CORNER_LEFT_UPPER);
    // Total Lots: 11 | Commission: 97.6 (Avg:6.93)
    nXPos = DRAW_ROW_SPACE * 2;
    double dAvgCommission = 0.0;
    if(dCount>0.0)  dAvgCommission = dSumCommission/dCount;
    txt = "Total Lots: "+DoubleToStr(dCount,2)+" | Commission: "+DoubleToStr(dSumCommission,2)+" | Avg: "+DoubleToStr(dAvgCommission,2);
    DrawCornerText(txt,nXPos,nYPosIndex,clrRed,nTopLowFontSize,CORNER_LEFT_UPPER);
    
    
    //+------------------------------------------------------------------+
    //| Draw Center Symbol                                                    
    //+------------------------------------------------------------------+
    for(int i = 0;i<nSymbrlCnt;++i)
    {
        int nYHeight = (i+1)*DRAW_CNT_IN_GROUP;     // Current Total Height
        nYPosIndex = nYHeight;
        nXPos = 0;
        
        for(int n = 1;n<10;++n)
        {
            if(nYHeight > DRAW_ROW_GROUP_CNT*DRAW_CNT_IN_GROUP*n)
            {
                nYPosIndex = nYHeight-((DRAW_ROW_GROUP_CNT*n+1)*DRAW_CNT_IN_GROUP)+DRAW_CNT_IN_GROUP;
                nXPos = DRAW_ROW_SPACE * n;
            }
        }

        DrawHistoryOrderOnChar(lsSymbol[i],1,false,nXPos+6,nYPosIndex,true);
    }
    
    
    //+------------------------------------------------------------------+
    //| Draw Bottom                                                    
    //+------------------------------------------------------------------+
    // Balance: 423.35 | Equity: 386.34
    nYPosIndex = 0;
    nXPos = DRAW_ROW_SPACE * 0 + 10;
    string sAccountMargin = "0.0";
    if(AccountMargin()>0)
    	sAccountMargin = DoubleToStr(AccountEquity()/AccountMargin()*100,2);
    txt = "Balance: "+DoubleToStr(AccountBalance(),2) + " ｜ Equity: "+DoubleToStr(AccountEquity(),2);
    DrawCornerText(txt,nXPos,nYPosIndex,clrOrange,nTopLowFontSize,CORNER_LEFT_LOWER);
    
    // FreeMargin: 315.05 | Margin: 300%
    nXPos = DRAW_ROW_SPACE * 2;
    txt = "FreeMargin: "+DoubleToStr(AccountFreeMargin(),2) + " ｜ Margin: "+sAccountMargin+"%";
    DrawCornerText(txt,nXPos,nYPosIndex,clrOrange,nTopLowFontSize,CORNER_LEFT_LOWER);
	
	// MaxStopProfit: 2844.3 | MaxStopLoss: 1255 | NoStopLess: 3
	OrderInfo info(Symbol(),true);
    nXPos = DRAW_ROW_SPACE * 4;
	txt = "TotalStopLoss: -" + DoubleToStr(info.dMaxStopLess, 2);
	if(0.0 < AccountBalance())
        txt += " ｜ TotalStopLossRadio: " + DoubleToStr(info.dMaxStopLess/AccountBalance()*100, 2)+"%";
    if(0.0 < info.dMaxStopProfit)
        txt += " ｜ TotalStopProfit: " + DoubleToStr(info.dMaxStopProfit, 2);
    if(0 < info.nNoStopLessCnt)
        txt += " ｜NoStopLess：" + IntegerToString(info.nNoStopLessCnt);
	DrawCornerText(txt,nXPos,nYPosIndex,clrOrange,nTopLowFontSize,CORNER_LEFT_LOWER);
    
    /*/ 每日一读
    nXPos = 0;
    nYPosIndex = 5;
    for(int i = WARING_EVERYDAY_LEN-1;i>=0;--i)
    {
        DrawCornerText(g_waringEveryday[i],nXPos,nYPosIndex,clrOrange,nWaringFontSize,CORNER_LEFT_LOWER);
        ++nYPosIndex;
    }
    
    // 交易思想
    nXPos = 0;
    nYPosIndex += 2;
    for(int i = WARING_MIND_LEN-1;i>=0;--i)
    {
        DrawCornerText(g_waringMind[i],nXPos,nYPosIndex,clrOrange,nWaringFontSize,CORNER_LEFT_LOWER);
        ++nYPosIndex;
    }
    */
    
    // 分析历史订单
    /* （WaltzMAMACD无关联度测试结果：RSI稳定能微弱提到胜率，上蹦下跳极值反之，WR指标无关联）
    bool hasCurSymbol = false;
    int nIndex = 0;
    int nBarCnt = 1440;
    int nAnalysisPeriod = 21;
    for(int i = 0;i<ANALYSIS_SYMBOL_RATE_CNT;++i)
    {
        if(g_arySymbolRate[i]=="")
            continue;
        if(g_arySymbolRate[i]==Symbol())
            hasCurSymbol = true;
        
        nXPos = nIndex*3+0;
        txt = AnalysisSymbolRate(g_arySymbolRate[i],PERIOD_M1,nAnalysisPeriod,nBarCnt);
        DrawCornerText(txt,10,nXPos,clrOrange,10,CORNER_RIGHT_UPPER);
        nXPos = nIndex*3+1;
        txt = AnalysisSymbolRate(g_arySymbolRate[i],PERIOD_M5,nAnalysisPeriod,nBarCnt);
        DrawCornerText(txt,10,nXPos,clrOrange,10,CORNER_RIGHT_UPPER);
        //nXPos = i*4+2;
        //txt = AnalysisSymbolRate(g_arySymbolRate[i],PERIOD_M30,nAnalysisPeriod,nBarCnt);
        //DrawCornerText(txt,10,nXPos,clrOrange,10,CORNER_RIGHT_UPPER);
        ++nIndex;
    }
    if(!hasCurSymbol)
    {
        nXPos = nIndex*3+0;
        txt = AnalysisSymbolRate(Symbol(),PERIOD_M1,nAnalysisPeriod,nBarCnt);
        DrawCornerText(txt,10,nXPos,clrOrange,10,CORNER_RIGHT_UPPER);
        nXPos = nIndex*3+1;
        txt = AnalysisSymbolRate(Symbol(),PERIOD_M5,nAnalysisPeriod,nBarCnt);
        DrawCornerText(txt,10,nXPos,clrOrange,10,CORNER_RIGHT_UPPER);
    }
    */
}

//+------------------------------------------------------------------+
//| 分析历史订单数据                                                 |
//+------------------------------------------------------------------+
#define SYMBOL_RATE_ARRY_CNT 10                       // 数组长度,应该是偶数，因为需要合并超卖超卖
#define SYMBOL_RATE_GROUP (100/SYMBOL_RATE_ARRY_CNT)  // 按照百分比分组
string AnalysisSymbolRate(string sSymbol,int nTimeFrame, int nAnalysisPeriod,int nBarCnt)
{
    nBarCnt = MathMin(nBarCnt,iBars(sSymbol,nTimeFrame));
    if(nBarCnt == 0)
       return "null bars";
    
    double nArryCnt[SYMBOL_RATE_ARRY_CNT] = {0};
    for(int i = 0;i<nBarCnt;++i)
    {
        double d = iRSI(sSymbol,nTimeFrame,nAnalysisPeriod,PRICE_CLOSE,i);
        double y = NormalizeDouble((d-MathMod(d,SYMBOL_RATE_GROUP))/SYMBOL_RATE_GROUP,0); //取整数，然后套入到区间，接着四舍五入
        nArryCnt[int(y)] += 1.0;
    }
    
    string s = sSymbol+" "+(nTimeFrame<10?"0":"")+IntegerToString(nTimeFrame)+"F: ";
    /*
    for(int i = 0;i<SYMBOL_RATE_ARRY_CNT;++i)
    {
        double nCnt = nArryCnt[i];
        nArryCnt[i] = (double)nCnt/nBarCnt*100; // 总数换算为百分比 
        s+=DoubleToStr(nArryCnt[i],2)+"%";
        if(i!=(SYMBOL_RATE_ARRY_CNT-1))
            s+="|";
    }
    */
    int nNew_ArryCnt = SYMBOL_RATE_ARRY_CNT/2;
    for(int i = 0,n=(SYMBOL_RATE_ARRY_CNT-1);i<nNew_ArryCnt;++i,--n)
    {
        double nCnt = nArryCnt[i]+nArryCnt[n];
        nArryCnt[i] = (double)nCnt/nBarCnt*100; // 总数换算为百分比 
        s+=(nArryCnt[i]<10?"0":"")+DoubleToStr(nArryCnt[i],2)+"%";
        if(i!=(nNew_ArryCnt-1))
            s+="|";
    }
    return s;
}